home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (c) 1993 Christopher J. Kane. All rights reserved.
- *
- * This software is subject to the terms of the MiscKit license
- * agreement. Refer to the license document included with the
- * MiscKit distribution for these terms.
- *
- * Version: 1.2 (25 June 1994)
- *
- * Licinda Woudberg - licinda@Black_Albatross.otago.ac.nz
- * 25 June 1994
- * Changed: -replaceAll.... works so that it can handle both plain
- * text & rtf style document. Still need to double check rtfd's
- * Changed: -replaceSelection:
- * now sends textDidChange: notice to the delegate
- */
-
- #import <misckit/MiscSearchText.h>
- #import <misckit/MiscTBMK.h>
- #import <misckit/regexpr.h>
-
- @implementation Text (SearchText)
-
- - (oneway void)makeSelectionVisible
- {
- [self scrollSelToVisible];
- }
-
- - (int)replaceAll:(const char *)pattern with:(const char *)replacement mode:(SearchMode)mode regexpr:(BOOL)regexpr cases:(BOOL)cases
- {
- unsigned char fm[256], tr[256];
- struct re_pattern_buffer rpat;
- Misc_TBMKpattern lpat = NULL;
- NXStream *in_strm = NULL;
- int s1=0, e1=0, s2=0, e2=0, ret_val=0, plen=0, rlen=0, pos=0, size=0, p=0, searchTextMaxSize=0;
-
- /* Known bug: the delegate will not get textWillChange:, textDidChange: notification messages */
- if ( (sp0.cp < 0) && (mode != TextEdgeToTextEdge) )
- return SEARCH_NO_SELECTION;
- if ( ![self isEditable] )
- return SEARCH_CANNOT_WRITE;
- switch ( mode ) /* setup start and end points for the search */
- {
- case TextEdgeToTextEdge:
- case SelStartToSelStart:
- case SelEndToSelEnd:
- s1 = 0; e1 = textLength; break;
- case TextEdgeToSelStart:
- s1 = 0; e1 = sp0.cp; break;
- case TextEdgeToSelEnd:
- s1 = 0; e1 = spN.cp; break;
- case SelStartToSelEnd:
- s1 = sp0.cp; e1 = spN.cp - sp0.cp; break;
- case SelStartToTextEdge:
- s1 = sp0.cp; e1 = textLength - sp0.cp; break;
- case SelEndToTextEdge:
- s1 = spN.cp; e1 = textLength - spN.cp; break;
- case SelEndToSelStart:
- s1 = 0; e1 = sp0.cp;
- s2 = spN.cp; e2 = textLength - spN.cp; break;
- default:
- return SEARCH_INVALID_ARGUMENT;
- }
- searchTextMaxSize = s1 + e1;
- plen = strlen(pattern); /* pattern length */
- rlen = strlen(replacement); /* replacement length */
- if (regexpr)
- {
- /* dealing with a regular expression */
- char *str;
- int i;
-
- memset(&rpat, 0, sizeof(rpat));
- for ( i = 256; i--; )
- tr[i] = i;
- if (!cases)
- for ( i = 'A'; i <= 'Z'; i++ )
- tr[i] = i - 'A' + 'a';
- rpat.translate = tr;
- rpat.fastmap = fm;
- str = re_compile_pattern((char *)pattern, plen, &rpat);
- if (str != NULL)
- return (strcmp(str, "Out of memory") ? SEARCH_INVALID_REGEXPR : SEARCH_INTERNAL_ERROR);
- }
- else
- {
- /* dealing with a normal find & replace - setup the Pattern to search for */
- lpat = Misc_TBMKpattern_alloc(pattern, plen, 0, !cases);
- if (lpat == NULL)
- return SEARCH_INTERNAL_ERROR;
- }
- in_strm = NXOpenMemory(NULL, 0, NX_READWRITE); /* open the stream */
- if (in_strm == NULL)
- {
- ret_val = SEARCH_INTERNAL_ERROR;
- goto exit;
- }
- [self writeText:in_strm]; /* read the text into the stream */
- NXSeek(in_strm, 0, NX_FROMSTART); /* start at the begining */
- ret_val = 0; /* set the counter to zero */
-
-
- start_searching:
- if (NXUserAborted())
- {
- ret_val = SEARCH_ABORTED;
- goto exit;
- }
- if (regexpr)
- {
- /* regular expression search */
- p = -1;
- if ( s1 > e1)
- /* reached the end of the search area */
- goto exit;
- if ( s1 >= 0 )
- {
- searchTextMaxSize = s1 + e1;
- p = re_search_pattern(&rpat, in_strm->buf_base, searchTextMaxSize, s1, e1, 0);
- }
- if (p==-1 && e2!=0)
- {
- s1 = s2;
- e1 = e2;
- s2 = e2 = 0;
- goto start_searching;
- }
- if (p==-2)
- {
- ret_val = SEARCH_INTERNAL_ERROR;
- goto exit;
- }
- if (p>-1)
- {
- int newTextPos=0;
-
- pos = p;
- size = re_match_pattern(&rpat, in_strm->buf_base, searchTextMaxSize, pos, 0);
- if (size<0)
- {
- ret_val = SEARCH_INTERNAL_ERROR;
- goto exit;
- }
- newTextPos = (ret_val * (rlen - size)) + pos;
- [self setSel:newTextPos :(newTextPos+size) ];
- [self makeSelectionVisible];
- [self replaceSel:replacement];
- s1 = p + rlen;
- ret_val++;
- goto start_searching;
- }
- }
- else
- {
- /* normal find & replace search */
- p = 0;
- if (s1 > e1)
- /* reached the end of the search area */
- goto exit;
- if (s1 >= 0)
- p = Misc_TBMKsearch_memory(lpat, in_strm->buf_base + s1, e1, 0, &pos);
- if (p < 0)
- {
- /* couldn't find a match for some reason */
- ret_val = SEARCH_INTERNAL_ERROR;
- goto exit;
- }
- if (p == 0 && e2 != 0)
- {
- /* couldn't find a match in the 1st selection area - there is a 2nd area to check */
- s1 = s2;
- e1 = e2;
- s2 = e2 = 0;
- goto start_searching;
- }
- if (p > 0)
- {
- /* found a match */
- int newTextPos=0;
-
- pos = pos + s1; /* set selection variables */
- newTextPos = (ret_val * (rlen - plen)) + pos;
- size = plen;
- ret_val++;
- [self setSel:newTextPos :(newTextPos+size) ]; /* select the area */
- [self makeSelectionVisible];
- [self replaceSel:replacement]; /* replace the area */
- s1 = pos + plen; /* reset the start position */
- goto start_searching;
- }
- }
-
- exit:
- Misc_TBMKpattern_free(&lpat);
- if (in_strm != NULL)
- NXCloseMemory(in_strm, NX_FREEBUFFER);
- return ret_val;
- }
-
- - (oneway void)replaceSelection:(const char *)replacement
- {
- if ([self isEditable]) {
- if (delegate && [delegate respondsTo:@selector(textWillChange:)])
- [delegate textWillChange:self];
- [self replaceSel:replacement];
- if (delegate && [delegate respondsTo:@selector(textDidChange:)])
- [delegate textDidChange:self];
- }
- }
-
- - (int)searchFor:(const char *)pattern mode:(SearchMode)mode reverse:(BOOL)rev regexpr:(BOOL)regexpr cases:(BOOL)cases position:(out int *)pos size:(out int *)size
- {
- unsigned char fm[256], tr[256];
- struct re_pattern_buffer rpat;
- Misc_TBMKpattern lpat=NULL;
- NXStream *in_strm=NULL;
- int s1=0, e1=0, s2=0, e2=0, ret_val, plen, p, position;
-
- if (sp0.cp<0 && mode!=TextEdgeToTextEdge)
- return SEARCH_NO_SELECTION;
- if (rev)
- switch (mode)
- {
- case TextEdgeToSelStart: s1 = textLength-1; e1 = sp0.cp-textLength; break;
- case TextEdgeToSelEnd: s1 = textLength-1; e1 = spN.cp-textLength; break;
- case TextEdgeToTextEdge: s1 = textLength-1; e1 = -textLength; break;
- case SelStartToSelEnd: s1 = sp0.cp-1; e1 = -sp0.cp+1; s2 = textLength-1; e2 = spN.cp-textLength+1; break;
- case SelStartToTextEdge: s1 = sp0.cp-1; e1 = -sp0.cp+1; break;
- case SelStartToSelStart: s1 = sp0.cp-1; e1 = -sp0.cp+1; s2 = textLength-1; e2 = sp0.cp-textLength+1; break;
- case SelEndToTextEdge: s1 = spN.cp-1; e1 = -spN.cp+1; break;
- case SelEndToSelStart: s1 = spN.cp-1; e1 = sp0.cp-spN.cp+1; break;
- case SelEndToSelEnd: s1 = spN.cp-1; e1 = -spN.cp+1; s2 = textLength-1; e2 = spN.cp-textLength+1; break;
- default: return SEARCH_INVALID_ARGUMENT;
- }
- else
- switch (mode)
- {
- case TextEdgeToSelStart: s1 = 0; e1 = sp0.cp; break;
- case TextEdgeToSelEnd: s1 = 0; e1 = spN.cp; break;
- case TextEdgeToTextEdge: s1 = 0; e1 = textLength; break;
- case SelStartToSelEnd: s1 = sp0.cp; e1 = spN.cp-sp0.cp; break;
- case SelStartToTextEdge: s1 = sp0.cp; e1 = textLength-sp0.cp; break;
- case SelStartToSelStart: s1 = sp0.cp; e1 = textLength-sp0.cp; s2 = 0; e2 = sp0.cp; break;
- case SelEndToTextEdge: s1 = spN.cp; e1 = textLength-spN.cp; break;
- case SelEndToSelStart: s1 = spN.cp; e1 = textLength-spN.cp; s2 = 0; e2 = sp0.cp; break;
- case SelEndToSelEnd: s1 = spN.cp; e1 = textLength-spN.cp; s2 = 0; e2 = spN.cp; break;
- default: return SEARCH_INVALID_ARGUMENT;
- }
- plen = strlen(pattern);
- if (regexpr)
- {
- char *str;
- int i;
- memset(&rpat, 0, sizeof(rpat));
- for(i=256; i--;)
- tr[i] = i;
- if (!cases)
- for(i='A'; i<='Z'; i++) tr[i] = i-'A'+'a';
- rpat.translate = tr;
- rpat.fastmap = fm;
- str = re_compile_pattern((char *)pattern, plen, &rpat);
- if (str!=NULL)
- return (strcmp(str, "Out of memory")?SEARCH_INVALID_REGEXPR:SEARCH_INTERNAL_ERROR);
- }
- else
- {
- lpat = Misc_TBMKpattern_alloc(pattern, plen, rev, !cases);
- if (lpat==NULL)
- return SEARCH_INTERNAL_ERROR;
- }
- in_strm = NXOpenMemory(NULL, 0, NX_READWRITE);
- if (in_strm==NULL)
- {
- ret_val = SEARCH_INTERNAL_ERROR;
- goto exit;
- }
- [self writeText:in_strm];
- NXSeek(in_strm, 0, NX_FROMSTART);
- ret_val = 0;
- start_searching:
- if (NXUserAborted())
- {
- ret_val = SEARCH_ABORTED;
- goto exit;
- }
- if (regexpr)
- {
- p = -1;
- if (s1>=0)
- p = re_search_pattern(&rpat, in_strm->buf_base, textLength, s1, e1, 0);
- if (p==-1 && e2!=0)
- {
- s1 = s2;
- e1 = e2;
- s2 = e2 = 0;
- goto start_searching;
- }
- if (p==-2)
- {
- ret_val = SEARCH_INTERNAL_ERROR;
- goto exit;
- }
- if (p>-1)
- {
- *pos = p;
- *size = re_match_pattern(&rpat, in_strm->buf_base, textLength, p, 0);
- if (*size<0)
- {
- ret_val = SEARCH_INTERNAL_ERROR;
- goto exit;
- }
- ret_val = 1;
- }
- }
- else
- {
- p = 0;
- if (s1>=0)
- p = Misc_TBMKsearch_memory(lpat, in_strm->buf_base+s1, e1, 0, &position);
- if (p<0)
- {
- ret_val = SEARCH_INTERNAL_ERROR;
- goto exit;
- }
- if (p==0 && e2!=0)
- {
- s1 = s2;
- e1 = e2;
- s2 = e2 = 0;
- goto start_searching;
- }
- if (p>0)
- {
- *pos = position+s1;
- *size = plen;
- ret_val = 1;
- }
- }
- exit:
- Misc_TBMKpattern_free(&lpat);
- if (in_strm!=NULL)
- NXCloseMemory(in_strm, NX_FREEBUFFER);
- return ret_val;
- }
-
- - (oneway void)selectTextFrom:(int)start to:(int)end
- {
- if ([self isSelectable] && start<=end && 0<=start)
- [self setSel:start :end];
- }
-
- - (int)setRegExprSyntax:(int)syntax
- {
- return re_set_syntax(syntax);
- }
-
- - (void)writeSelectionToPasteboard:(in Pasteboard *)pboard asType:(in NXAtom)type
- {
- char text[spN.cp-sp0.cp+1];
- [self getSubstring:text start:sp0.cp length:spN.cp-sp0.cp];
- text[spN.cp-sp0.cp] = '\0';
- if (*text!='\0')
- {
- [pboard declareTypes:&type num:1 owner:NULL];
- [pboard writeType:type data:text length:spN.cp-sp0.cp];
- }
- }
-
- @end
-